// IO Monad         //当一个函数返回一个函子的时候就可以使用  解决函子嵌套的问题   
//合并函数且返回值 => .map函数       合并函数返回函子  => .monade方法
const fs = require('fs')
const fp = require('lodash/fp')

class IO {
    static of (value) {
        return new IO(function() {
            return value
        })
    }

    constructor (fn) {
        this._value = fn;
    }

    map (fn) {
        return new IO(fp.flowRight(fn, this._value))
    }

    //将map中的组合函数拍扁 不用再层层调用
    join () {
        return this._value()
    }

    //同时调用 map 和 join函数
    flatMap (fn) {
        return this.map(fn).join();
    }
}

//读取文件内容并打印该内容
//读取文件函数   为避免副作用将其封装成了一个函数 使其成为一个纯函数
let readFile = function (filename) {
    return new IO(function () {
        return fs.readFileSync(filename, 'utf-8')
    })
}

//接收打印的内容  
let print = function (x) {
    return new IO(function () {
        console.log(x);             //打印结果  文本内容
        return x
    })
}

let r = readFile('package.json')      //此时已经读取完文件即获取文件内容 返回IO()
            //处理文件内容的值
            // .map(x => x.toUpperCase())
            //使用loadash中的toUpper
            .map(fp.toUpper)
            //先调用map返回 IO( print(文本内容 )) 最里面为readFile 文本内容 其次是print()  最外层为封装两者
            //后调用join  则返回IO(... retrun 文本内容 ) 最里面为readFile 返回的文本内容 外层是print返回的IO
            .flatMap(print)  
            //调用内部的_value  即print  IO内的函数        输出并返回文本内容
            .join()


console.log(r);                 //打印结果: 文本内容